package apiUtils;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import apiUtils.params.Params;
import appUtils.LogUtil;
import constant.ApiConstants;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * APIs base class
 * okhtpp util class
 * Created by zy on 2017/4/10.
 */

public class BaseAPIS {
    public final static int FAILURE = 0;
    public final static int RESPONSE_IS_ERROR = 1;
    public final static int RESPONSE_IS_NULL = 2;
    private OkHttpClient mOkHttpClient;
    private Call call;

    private BaseAPIS() {
        mOkHttpClient = new OkHttpClient.Builder().connectTimeout(ApiConstants.TIME_OUT, TimeUnit.SECONDS).readTimeout(ApiConstants.TIME_OUT, TimeUnit.SECONDS).build();
    }

    public static BaseAPIS getInstance() {
        return Holder.baseAPIS;
    }

    /**
     * 默认为get方法
     * 异步
     *
     * @param tag
     * @param url
     * @param callback
     */
    public void get(final String tag, String url, Params apiParams, final CallBack callback) {
        url = bufferUrl(url, apiParams);
        LogUtil.log(url);
        call = mOkHttpClient.newCall(new Request.Builder().tag(tag).url(url).build());
        dealCall(tag, call, callback);
    }

    /**
     * 异步post方法
     *
     * @param tag
     * @param url
     * @param callback
     */
    public void post(String tag, String url, RequestBody body, CallBack callback) {
        url = bufferUrl(url, null);
        LogUtil.log(url);
        call = mOkHttpClient.newCall(new Request.Builder().tag(tag).url(url).post(body).build());
        dealCall(tag, call, callback);
    }

    /**
     * 同步的get
     *
     * @param tag
     * @param url
     * @return
     * @throws IOException
     */
    public void syncGet(String tag, String url, Params apiParams, CallBack callBack) throws IOException {
        url = bufferUrl(url, apiParams);
        LogUtil.log(tag, url);
        call = mOkHttpClient.newCall(new Request.Builder().tag(tag).url(url).get().build());
        syncDealCall(tag, call, callBack);
    }

    /**
     * 同步的post
     *
     * @param tag
     * @param url
     * @param requestBody
     * @return
     * @throws IOException
     */
    public void syncPost(String tag, String url, RequestBody requestBody, CallBack callBack) throws IOException {
        url = bufferUrl(url, null);
        LogUtil.log(url);
        call = mOkHttpClient.newCall(new Request.Builder().tag(tag).url(url).post(requestBody).build());
        syncDealCall(tag, call, callBack);
    }

    /**
     * 同步请求
     *
     * @param tag
     * @param call
     * @return
     * @throws IOException
     */
    private void syncDealCall(final String tag, final Call call, final CallBack callBack) throws IOException {
        Observable.just(1).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).map(new Function<Integer, Response>() {
            @Override
            public Response apply(Integer integer) throws Exception {
                return call.execute();
            }
        }).subscribe(new Consumer<Response>() {
            @Override
            public void accept(Response response) throws Exception {
                if (response.body() != null) {
                    if (response.isSuccessful()) {
                        callBack.onSuccess(call, response.body().string());
                    } else {
                        LogUtil.log(tag, " onResponse failure");
                        if (null != callBack) {
                            callBack.onError(RESPONSE_IS_ERROR);
                        }
                    }
                } else {
                    LogUtil.log(tag, " response body = null");
                    if (null != callBack) {
                        callBack.onError(RESPONSE_IS_NULL);
                    }
                }
            }
        });
    }

    /**
     * 异步请求
     *
     * @param tag
     * @param call
     * @param callback
     */
    private void dealCall(final String tag, final Call call, final CallBack callback) {

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.log(tag, " onFailure IOException = " + e.getMessage());
                if (null != callback) {
                    callback.onError(FAILURE);
                }
            }

            @Override
            public void onResponse(final Call call, final Response response) throws IOException {
                LogUtil.log(tag, " onResponse code = " + response.code());
                if (null != response.body()) {
                    if (response.isSuccessful()) {
                        if (null != callback) {
                            callback.onSuccess(call, response.body().string());
                        }
                    } else {
                        LogUtil.log(tag, " response body = null");
                        if (null != callback) {
                            callback.onError(RESPONSE_IS_ERROR);
                        }
                    }
                } else {
                    LogUtil.log(tag, " onResponse failure");
                    if (null != callback) {
                        callback.onError(RESPONSE_IS_NULL);
                    }
                }
            }
        });
    }

    private String bufferUrl(String url, Params apiParams) {
        return ApiConstants.sUrl + url + (apiParams == null ? "" : apiParams.toString());
    }

    /**
     * 取消所有请求
     */
    public void destroy() {
        if (null != mOkHttpClient) {
            mOkHttpClient.dispatcher().cancelAll();
        }
    }

    /**
     * 通过tag取消请求
     *
     * @param tag
     */
    public void cancelByTag(String tag) {
        if (call != null) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    private static final class Holder {
        private static BaseAPIS baseAPIS = new BaseAPIS();
    }

}
